<template>
  <div class="modern-picture-list">
    <!-- 骨架屏加载 -->
    <div v-if="loading && dataList.length === 0" class="skeleton-container">
      <div 
        v-for="i in 12" 
        :key="i" 
        class="skeleton-card"
        v-motion
        :initial="{ opacity: 0, scale: 0.9 }"
        :enter="{ 
          opacity: 1, 
          scale: 1, 
          transition: { 
            duration: 400, 
            delay: i * 50,
            ease: 'easeOut' 
          } 
        }"
      >
        <div class="skeleton-image"></div>
        <div class="skeleton-content">
          <div class="skeleton-title"></div>
          <div class="skeleton-tags">
            <div class="skeleton-tag"></div>
            <div class="skeleton-tag"></div>
          </div>
        </div>
      </div>
    </div>

    <!-- 图片网格 -->
    <div 
      v-else-if="viewMode === 'grid'" 
      class="picture-grid"
      :class="{ 'grid-loading': loading }"
    >
      <div
        v-for="(picture, index) in dataList"
        :key="picture.id"
        class="picture-card-wrapper"
        v-motion
        :initial="{ opacity: 0, y: 30, scale: 0.9 }"
        :enter="{ 
          opacity: 1, 
          y: 0, 
          scale: 1,
          transition: { 
            duration: 500, 
            delay: index * 100,
            ease: 'easeOut' 
          } 
        }"
        @click="doClickPicture(picture)"
      >
        <div class="picture-card glass-card">
          <!-- 图片容器 -->
          <div class="image-container">
            <div 
              :ref="(el) => setImageRef(el, picture.id)"
              class="lazy-image-wrapper"
              :data-src="picture.thumbnailUrl ?? picture.url"
              :data-alt="picture.name"
            >
              <!-- 占位符 -->
              <div 
                v-if="picture.id && !loadedImages.has(picture.id)" 
                class="image-placeholder"
                :class="{ 'loading': picture.id && loadingImages.has(picture.id) }"
              >
                <div class="placeholder-content">
                  <PictureOutlined class="placeholder-icon" />
                  <div v-if="picture.id && loadingImages.has(picture.id)" class="loading-spinner">
                    <LoadingOutlined />
                  </div>
                </div>
              </div>
              
              <!-- 实际图片 -->
              <img
                v-if="picture.id && loadedImages.has(picture.id)"
                :src="picture.thumbnailUrl ?? picture.url"
                :alt="picture.name ?? ''"
                class="picture-image"
                :class="{ 'fade-in': picture.id && justLoadedImages.has(picture.id) }"
                @load="onImageLoad"
                @error="onImageError"
              />
            </div>
            <div class="image-overlay">
              <div class="overlay-content">
                <div class="action-buttons">
                  <button 
                    class="action-btn preview-btn"
                    @click.stop="doPreview(picture)"
                    title="预览"
                  >
                    <EyeOutlined />
                  </button>
                  <button 
                    class="action-btn share-btn"
                    @click.stop="doShare(picture, $event)"
                    title="分享"
                  >
                    <ShareAltOutlined />
                  </button>
                  <button 
                    v-if="canEdit"
                    class="action-btn edit-btn"
                    @click.stop="doEdit(picture, $event)"
                    title="编辑"
                  >
                    <EditOutlined />
                  </button>
                  <button 
                    v-if="canDelete"
                    class="action-btn delete-btn"
                    @click.stop="doDelete(picture, $event)"
                    title="删除"
                  >
                    <DeleteOutlined />
                  </button>
                </div>
              </div>
            </div>
            
            <!-- 加载指示器 -->
            <div class="image-loading" v-if="picture.id && loadingImages.has(picture.id)">
              <LoadingOutlined class="loading-spinner" />
            </div>
          </div>

          <!-- 卡片内容 -->
          <div class="card-content">
            <h3 class="picture-title">{{ picture.name }}</h3>
            <div class="picture-meta">
              <div class="category-tag">
                <TagOutlined />
                <span>{{ picture.category ?? '默认' }}</span>
              </div>
              <div class="picture-size">{{ formatFileSize(picture.picSize || 0) }}</div>
            </div>
            <div class="picture-tags" v-if="picture.tags && picture.tags.length > 0">
              <span 
                v-for="tag in picture.tags.slice(0, 3)" 
                :key="tag"
                class="tag-item"
              >
                {{ tag }}
              </span>
              <span v-if="picture.tags.length > 3" class="more-tags">
                +{{ picture.tags.length - 3 }}
              </span>
            </div>
          </div>

          <!-- 悬浮效果 -->
          <div class="card-glow"></div>
        </div>
      </div>
    </div>

    <!-- 瀑布流布局 -->
    <div 
      v-else-if="viewMode === 'masonry'" 
      class="masonry-container"
      ref="masonryRef"
    >
      <div
        v-for="(picture, index) in dataList"
        :key="picture.id"
        class="masonry-item"
        :style="{ height: `${getMasonryHeight(index)}px` }"
        v-motion
        :initial="{ opacity: 0, scale: 0.8 }"
        :enter="{ 
          opacity: 1, 
          scale: 1,
          transition: { 
            duration: 600, 
            delay: index * 50,
            ease: 'backOut' 
          } 
        }"
        @click="doClickPicture(picture)"
      >
        <div class="masonry-card glass-card">
          <div class="masonry-image-container">
            <img
              :src="picture.thumbnailUrl ?? picture.url"
                :alt="picture.name"
              class="masonry-image"
            />
            <div class="masonry-overlay">
              <div class="masonry-actions">
                <button class="masonry-action-btn" @click.stop="doPreview(picture)">
                  <EyeOutlined />
                </button>
                <button class="masonry-action-btn" @click.stop="doShare(picture, $event)">
                  <ShareAltOutlined />
                </button>
              </div>
            </div>
          </div>
          <div class="masonry-content">
            <h4 class="masonry-title">{{ picture.name }}</h4>
            <div class="masonry-tags">
              <span 
                v-for="tag in picture.tags?.slice(0, 2)" 
                :key="tag"
                class="masonry-tag"
              >
                {{ tag }}
              </span>
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 列表布局 -->
    <div v-else class="list-view">
      <div
        v-for="(picture, index) in dataList"
        :key="picture.id"
        class="list-item glass-card"
        v-motion
        :initial="{ opacity: 0, x: -30 }"
        :enter="{ 
          opacity: 1, 
          x: 0,
          transition: { 
            duration: 400, 
            delay: index * 80,
            ease: 'easeOut' 
          } 
        }"
        @click="doClickPicture(picture)"
      >
        <div class="list-image">
          <img
                :src="picture.thumbnailUrl ?? picture.url"
            :alt="picture.name ?? ''"
          />
        </div>
        <div class="list-content">
          <h3 class="list-title">{{ picture.name }}</h3>
          <div class="list-meta">
            <span class="list-category">{{ picture.category ?? '默认' }}</span>
            <span class="list-size">{{ formatFileSize(picture.picSize || 0) }}</span>
            <span class="list-date">{{ formatDate(picture.createTime || '') }}</span>
          </div>
          <div class="list-tags">
            <span 
              v-for="tag in picture.tags?.slice(0, 5)" 
              :key="tag"
              class="list-tag"
            >
              {{ tag }}
            </span>
          </div>
        </div>
        <div class="list-actions">
          <button class="list-action-btn" @click.stop="doPreview(picture)">
            <EyeOutlined />
          </button>
          <button class="list-action-btn" @click.stop="doShare(picture, $event)">
            <ShareAltOutlined />
          </button>
          <button 
            v-if="canEdit"
            class="list-action-btn"
            @click.stop="doEdit(picture, $event)"
          >
            <EditOutlined />
          </button>
          <button 
            v-if="canDelete"
            class="list-action-btn danger"
            @click.stop="doDelete(picture, $event)"
          >
            <DeleteOutlined />
          </button>
        </div>
      </div>
    </div>

    <!-- 加载更多指示器 -->
    <div v-if="loading && dataList.length > 0" class="loading-more">
      <div class="loading-spinner-container">
        <div class="spinner-ring"></div>
        <span class="loading-text">加载更多图片...</span>
      </div>
    </div>

    <!-- 图片预览模态框 -->
    <a-modal
      v-model:open="previewVisible"
      class="preview-modal"
      :footer="null"
      :width="800"
      centered
    >
      <div class="preview-container" v-if="previewImage">
        <img
          :src="previewImage.url"
          :alt="previewImage.name ?? ''"
          class="preview-image"
        />
        <div class="preview-info">
          <h3>{{ previewImage.name }}</h3>
          <div class="preview-meta">
            <span>大小: {{ formatFileSize(previewImage.picSize || 0) }}</span>
            <span>分类: {{ previewImage.category ?? '默认' }}</span>
            <span>创建时间: {{ formatDate(previewImage.createTime || '') }}</span>
          </div>
          <div class="preview-tags" v-if="previewImage.tags?.length">
            <span 
              v-for="tag in previewImage.tags" 
              :key="tag"
              class="preview-tag"
            >
                    {{ tag }}
            </span>
          </div>
        </div>
      </div>
    </a-modal>

    <!-- 分享模态框 -->
    <ShareModal ref="shareModalRef" :link="shareLink || ''" title="分享图片" />
  </div>
</template>

<script setup lang="ts">
import { useRouter } from 'vue-router'
import { ref, computed, onMounted, nextTick, onUnmounted, watch, type ComponentPublicInstance } from 'vue'
import {
  DeleteOutlined,
  EditOutlined,
  SearchOutlined,
  ShareAltOutlined,
  EyeOutlined,
  LoadingOutlined,
  TagOutlined,
  PictureOutlined
} from '@ant-design/icons-vue'
import { deletePictureUsingPost } from '@/api/pictureController.ts'
import { message } from 'ant-design-vue'
import ShareModal from '@/components/ShareModal.vue'
import { gsap } from 'gsap'

interface Props {
  dataList?: API.PictureVO[]
  loading?: boolean
  showOp?: boolean
  canEdit?: boolean
  canDelete?: boolean
  viewMode?: string
  onReload?: () => void
}

const props = withDefaults(defineProps<Props>(), {
  dataList: () => [],
  loading: false,
  showOp: false,
  canEdit: false,
  canDelete: false,
  viewMode: 'grid',
})


// 新增状态
const previewVisible = ref(false)
const previewImage = ref<API.PictureVO | null>(null)
const masonryRef = ref<HTMLElement>()

// 分享相关
const shareModalRef = ref()
const shareLink = ref<string>()

// 懒加载相关状态
const loadedImages = ref(new Set<string>()) // 已加载的图片ID集合
const loadingImages = ref(new Set<string>()) // 正在加载的图片ID集合
const justLoadedImages = ref(new Set<string>()) // 刚加载完成的图片ID集合，用于动画
const imageRefs = ref(new Map<string, HTMLElement>()) // 图片元素引用映射
const intersectionObserver = ref<IntersectionObserver | null>(null)

const router = useRouter()

// 懒加载方法
const setImageRef = (el: Element | ComponentPublicInstance | null, pictureId: string | undefined) => {
  if (el && pictureId && el instanceof HTMLElement) {
    imageRefs.value.set(pictureId, el)
  }
}

// 初始化懒加载观察器
const initLazyLoading = () => {
  if (!window.IntersectionObserver) {
    // 不支持IntersectionObserver的浏览器直接加载所有图片
    props.dataList.forEach(picture => {
      if (picture.id) {
        loadImage(picture.id)
      }
    })
    return
  }

  intersectionObserver.value = new IntersectionObserver(
    (entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const element = entry.target as HTMLElement
          const src = element.getAttribute('data-src')
          const pictureId = Array.from(imageRefs.value.entries()).find(
            ([, el]) => el === element
          )?.[0]
          
          if (src && pictureId) {
            loadImage(pictureId)
            intersectionObserver.value?.unobserve(element)
          }
        }
      })
    },
    {
      rootMargin: '50px', // 提前50px开始加载
      threshold: 0.1 // 当10%可见时触发
    }
  )
}

// 加载单个图片
const loadImage = (pictureId: string) => {
  if (loadedImages.value.has(pictureId) || loadingImages.value.has(pictureId)) {
    return
  }

  const picture = props.dataList.find(p => p.id === pictureId)
  if (!picture) return

  loadingImages.value.add(pictureId)
  
  // 创建新的图片元素来预加载
  const img = new Image()
  img.onload = () => {
    loadedImages.value.add(pictureId)
    loadingImages.value.delete(pictureId)
    justLoadedImages.value.add(pictureId)
    
    // 2秒后移除fade-in动画类
    setTimeout(() => {
      justLoadedImages.value.delete(pictureId)
    }, 2000)
  }
  
  img.onerror = () => {
    loadingImages.value.delete(pictureId)
    console.error(`Failed to load image for picture ${pictureId}`)
  }
  
  img.src = picture.thumbnailUrl ?? picture.url ?? ''
}

// 观察所有图片元素
const observeImages = () => {
  if (!intersectionObserver.value) return
  
  imageRefs.value.forEach((element, pictureId) => {
    if (!loadedImages.value.has(pictureId)) {
      intersectionObserver.value?.observe(element)
    }
  })
}

// 清理懒加载状态
const resetLazyLoading = () => {
  loadedImages.value.clear()
  loadingImages.value.clear()
  justLoadedImages.value.clear()
  imageRefs.value.clear()
}

// 工具函数
const formatFileSize = (bytes: number): string => {
  if (!bytes) return '0 B'
  const k = 1024
  const sizes = ['B', 'KB', 'MB', 'GB']
  const i = Math.floor(Math.log(bytes) / Math.log(k))
  return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

const formatDate = (dateString: string): string => {
  if (!dateString) return ''
  return new Date(dateString).toLocaleDateString('zh-CN')
}

// 瀑布流高度计算
const getMasonryHeight = (index: number): number => {
  const baseHeight = 250
  const heights = [baseHeight, baseHeight + 50, baseHeight + 100, baseHeight + 150]
  return heights[index % heights.length]
}

// 图片加载处理
const onImageLoad = (event: Event) => {
  const img = event.target as HTMLImageElement
  gsap.fromTo(img, 
    { opacity: 0, scale: 1.1 },
    { opacity: 1, scale: 1, duration: 0.5, ease: 'power2.out' }
  )
}

const onImageError = (event: Event) => {
  const img = event.target as HTMLImageElement
  img.src = '/placeholder-image.png' // 错误占位图
}

// 跳转至图片详情页
const doClickPicture = (picture: API.PictureVO) => {
  router.push({
    path: `/picture/${picture.id}`,
  })
}

// 预览图片
const doPreview = (picture: API.PictureVO) => {
  previewImage.value = picture
  previewVisible.value = true
}

// 搜索
const doSearch = (picture: API.PictureVO, e: Event) => {
  e.stopPropagation()
  window.open(`/search_picture?pictureId=${picture.id}`)
}

// 编辑
const doEdit = (picture: API.PictureVO, e: Event) => {
  e.stopPropagation()
  router.push({
    path: '/add_picture',
    query: {
      id: picture.id,
      spaceId: picture.spaceId,
    },
  })
}

// 删除数据
const doDelete = async (picture: API.PictureVO, e: Event) => {
  e.stopPropagation()
  const id = picture.id
  if (!id) return
  
  const res = await deletePictureUsingPost({ id })
  if (res.data.code === 0) {
    message.success('删除成功')
    props.onReload?.()
  } else {
    message.error('删除失败')
  }
}

// 分享
const doShare = (picture: API.PictureVO, e: Event) => {
  e.stopPropagation()
  shareLink.value = `${window.location.protocol}//${window.location.host}/picture/${picture.id}`
  if (shareModalRef.value) {
    shareModalRef.value.openModal()
  }
}

// 生命周期钩子
onMounted(() => {
  initLazyLoading()
  nextTick(() => {
    observeImages()
  })
})

onUnmounted(() => {
  if (intersectionObserver.value) {
    intersectionObserver.value.disconnect()
  }
})

// 监听数据变化
watch(() => props.dataList, (newList, oldList) => {
  if (newList !== oldList) {
    resetLazyLoading()
    nextTick(() => {
      observeImages()
    })
  }
}, { deep: true })

// 监听imageRefs变化，当新的图片元素添加时自动观察
watch(imageRefs, () => {
  nextTick(() => {
    observeImages()
  })
}, { deep: true })
</script>

<style scoped>
.modern-picture-list {
  width: 100%;
}

/* 骨架屏样式 */
.skeleton-container {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.5rem;
  margin-bottom: 2rem;
}

.skeleton-card {
  background: rgba(255, 255, 255, 0.6);
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
  overflow: hidden;
  padding: 1rem;
}

.skeleton-image {
  width: 100%;
  height: 200px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: skeletonLoading 2s infinite;
  border-radius: 12px;
  margin-bottom: 1rem;
}

.skeleton-content {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.skeleton-title {
  height: 20px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: skeletonLoading 2s infinite;
  border-radius: 4px;
  width: 70%;
}

.skeleton-tags {
  display: flex;
  gap: 0.5rem;
}

.skeleton-tag {
  height: 16px;
  width: 60px;
  background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
  background-size: 200% 100%;
  animation: skeletonLoading 2s infinite;
  border-radius: 8px;
}

/* 网格布局 */
.picture-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1.5rem;
  margin-bottom: 2rem;
  width: 100%;
}

.picture-card {
  background: rgba(255, 255, 255, 0.8);
  backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 20px;
  overflow: hidden;
  cursor: pointer;
  transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
  position: relative;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}

.picture-card:hover {
  transform: translateY(-8px) scale(1.02);
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
  border-color: rgba(14, 165, 233, 0.3);
}

.image-container {
  position: relative;
  width: 100%;
  height: 200px;
  overflow: hidden;
  border-radius: 16px 16px 0 0;
}

.lazy-image-wrapper {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.picture-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: all 0.4s ease, opacity 0.5s ease;
  opacity: 1;
}

.picture-image.fade-in {
  animation: fadeInImage 0.8s ease-out;
}

/* 图片占位符样式 */
.image-placeholder {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
  border-radius: 16px 16px 0 0;
  transition: all 0.3s ease;
}

.image-placeholder.loading {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.placeholder-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  color: rgba(255, 255, 255, 0.8);
}

.placeholder-icon {
  font-size: 32px;
  opacity: 0.6;
  transition: all 0.3s ease;
}

.loading .placeholder-icon {
  opacity: 0.8;
  color: rgba(255, 255, 255, 0.9);
}

.loading-spinner {
  font-size: 20px;
  animation: spin 1s linear infinite;
}

.picture-card:hover .picture-image {
  transform: scale(1.1);
}

.image-overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(135deg, rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.7));
  opacity: 0;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

.picture-card:hover .image-overlay {
  opacity: 1;
}

.action-buttons {
  display: flex;
  gap: 0.75rem;
}

.action-btn {
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.9);
  color: #374151;
  cursor: pointer;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.125rem;
}

.action-btn:hover {
  background: white;
  color: #1f2937;
  transform: scale(1.1);
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}

/* 黑色模式下的按钮样式 */
[data-theme="dark"] .action-btn {
  background: rgba(31, 41, 55, 0.9);
  color: #e5e7eb;
  border: 1px solid rgba(75, 85, 99, 0.3);
}

[data-theme="dark"] .action-btn:hover {
  background: rgba(55, 65, 81, 0.95);
  color: #f3f4f6;
  border-color: rgba(107, 114, 128, 0.5);
  box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4);
}

.card-content {
  padding: 1.25rem;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 250, 252, 0.9));
  position: relative;
}

/* 黑色模式下的网格内容区域 */
[data-theme="dark"] .card-content {
  background: linear-gradient(135deg, rgba(31, 41, 55, 0.95), rgba(17, 24, 39, 0.9));
}

.picture-title {
  font-size: 1.125rem;
  font-weight: 700;
  color: #111827;
  margin: 0 0 0.75rem 0;
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-shadow: 0 2px 4px rgba(255, 255, 255, 0.9);
}

/* 黑色模式下的网格标题 */
[data-theme="dark"] .picture-title {
  color: #f9fafb;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.7);
}

.picture-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.75rem;
}

.category-tag {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  background: rgba(14, 165, 233, 0.1);
  color: #0ea5e9;
  padding: 0.25rem 0.5rem;
  border-radius: 12px;
  font-size: 0.75rem;
  font-weight: 500;
}

@keyframes skeletonLoading {
  0% { background-position: -200px 0; }
  100% { background-position: calc(200px + 100%) 0; }
}

/* 列表视图样式 */
.list-view {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin-bottom: 2rem;
}

.list-item {
  display: flex;
  align-items: center;
  padding: 1.5rem;
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
  cursor: pointer;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
}

.list-item:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
  background: rgba(255, 255, 255, 0.95);
}

.list-image {
  width: 120px;
  height: 80px;
  border-radius: 8px;
  overflow: hidden;
  flex-shrink: 0;
  margin-right: 1.5rem;
  position: relative;
}

.list-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.list-item:hover .list-image img {
  transform: scale(1.05);
}

.list-content {
  flex: 1;
  min-width: 0;
  padding-right: 1rem;
}

.list-title {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--primary-color);
  margin: 0 0 0.5rem 0;
  line-height: 1.4;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.list-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-bottom: 0.75rem;
}

.list-category,
.list-size,
.list-date {
  font-size: 0.85rem;
  color: #666;
  background: rgba(0, 0, 0, 0.05);
  padding: 0.25rem 0.5rem;
  border-radius: 4px;
}

/* 黑色模式下的列表样式 */
[data-theme="dark"] .list-size,
[data-theme="dark"] .list-date {
  color: #9ca3af;
  background: rgba(255, 255, 255, 0.1);
}

.list-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.list-tag {
  font-size: 0.75rem;
  color: #4A90E2;
  background: rgba(74, 144, 226, 0.1);
  border: 1px solid rgba(74, 144, 226, 0.2);
  padding: 0.25rem 0.5rem;
  border-radius: 12px;
  transition: all 0.2s ease;
}

.list-tag:hover {
  background: rgba(74, 144, 226, 0.2);
  border-color: rgba(74, 144, 226, 0.3);
}

.list-actions {
  display: flex;
  gap: 0.5rem;
  flex-shrink: 0;
}

.list-action-btn {
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.8);
  color: #666;
  cursor: pointer;
  transition: all 0.2s ease;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(10px);
  border: 1px solid rgba(255, 255, 255, 0.3);
}

/* 黑色模式下的列表操作按钮 */
[data-theme="dark"] .list-action-btn {
  background: rgba(31, 41, 55, 0.8);
  color: #9ca3af;
  border: 1px solid rgba(75, 85, 99, 0.3);
}

.list-action-btn:hover {
  background: rgba(74, 144, 226, 0.1);
  color: #4A90E2;
  transform: scale(1.1);
}

.list-action-btn.danger:hover {
  background: rgba(255, 77, 79, 0.1);
  color: #ff4d4f;
}

/* 响应式适配 */
@media (max-width: 768px) {
  .list-item {
    flex-direction: column;
    text-align: center;
    padding: 1rem;
  }
  
  .list-image {
    width: 100%;
    height: 120px;
    margin-right: 0;
    margin-bottom: 1rem;
  }
  
  .list-content {
    padding-right: 0;
    margin-bottom: 1rem;
  }
  
  .list-meta {
    justify-content: center;
  }
  
  .list-tags {
    justify-content: center;
  }
  
  .list-actions {
    justify-content: center;
  }
}

@media (max-width: 480px) {
  .list-meta {
    flex-direction: column;
    gap: 0.5rem;
    align-items: center;
  }
  
  .list-tags {
    max-width: 100%;
  }
  
  .list-action-btn {
    width: 40px;
    height: 40px;
  }
}

/* 瀑布流布局样式 */
.masonry-container {
  columns: 4;
  column-gap: 1rem;
  margin-bottom: 2rem;
}

.masonry-item {
  display: inline-block;
  width: 100%;
  margin-bottom: 1rem;
  break-inside: avoid;
  page-break-inside: avoid;
}

.masonry-card {
  position: relative;
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
  overflow: hidden;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
  transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
  cursor: pointer;
}

/* 黑色模式下的瀑布流卡片 */
[data-theme="dark"] .masonry-card {
  background: rgba(31, 41, 55, 0.9);
  border: 1px solid rgba(75, 85, 99, 0.3);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}

.masonry-card:hover {
  transform: translateY(-8px) scale(1.02);
  box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
}

.masonry-image-container {
  position: relative;
  width: 100%;
  overflow: hidden;
}

.masonry-image {
  width: 100%;
  height: auto;
  display: block;
  transition: transform 0.5s ease;
}

.masonry-card:hover .masonry-image {
  transform: scale(1.1);
}

.masonry-overlay {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    135deg, 
    rgba(0, 0, 0, 0.3) 0%, 
    transparent 50%,
    rgba(0, 0, 0, 0.3) 100%
  );
  opacity: 0;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  justify-content: center;
}

.masonry-card:hover .masonry-overlay {
  opacity: 1;
}

.masonry-actions {
  display: flex;
  gap: 0.75rem;
}

.masonry-action-btn {
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(10px);
  color: var(--primary-color);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.1rem;
  transition: all 0.3s ease;
  transform: translateY(20px);
}

/* 黑色模式下的瀑布流操作按钮 */
[data-theme="dark"] .masonry-action-btn {
  background: rgba(31, 41, 55, 0.9);
  border: 2px solid rgba(75, 85, 99, 0.5);
  color: #60a5fa;
}

.masonry-card:hover .masonry-action-btn {
  transform: translateY(0);
}

.masonry-action-btn:hover {
  background: var(--primary-color);
  color: white;
  transform: translateY(-2px) scale(1.1);
  box-shadow: 0 8px 20px rgba(14, 165, 233, 0.3);
}

.masonry-action-btn:nth-child(1) {
  transition-delay: 0.1s;
}

.masonry-action-btn:nth-child(2) {
  transition-delay: 0.2s;
}

.masonry-content {
  padding: 1rem;
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(248, 250, 252, 0.9));
  position: relative;
}

/* 黑色模式下的瀑布流内容区域 */
[data-theme="dark"] .masonry-content {
  background: linear-gradient(135deg, rgba(31, 41, 55, 0.95), rgba(17, 24, 39, 0.9));
}

.masonry-title {
  font-size: 0.95rem;
  font-weight: 700;
  color: #111827;
  margin: 0 0 0.75rem 0;
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  text-shadow: 0 2px 4px rgba(255, 255, 255, 0.9);
}

/* 黑色模式下的瀑布流标题 */
[data-theme="dark"] .masonry-title {
  color: #f9fafb;
  text-shadow: 0 2px 4px rgba(0, 0, 0, 0.7);
}

.masonry-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.masonry-tag {
  font-size: 0.75rem;
  color: #4A90E2;
  background: rgba(74, 144, 226, 0.1);
  border: 1px solid rgba(74, 144, 226, 0.2);
  padding: 0.3rem 0.6rem;
  border-radius: 12px;
  transition: all 0.2s ease;
}

.masonry-tag:hover {
  background: rgba(74, 144, 226, 0.2);
  border-color: rgba(74, 144, 226, 0.3);
}

/* 瀑布流响应式布局 */
@media (max-width: 1200px) {
  .masonry-container {
    columns: 3;
    column-gap: 0.75rem;
  }
}

@media (max-width: 768px) {
  .masonry-container {
    columns: 2;
    column-gap: 0.5rem;
  }
  
  .masonry-item {
    margin-bottom: 0.75rem;
  }
  
  .masonry-content {
    padding: 0.75rem;
  }
  
  .masonry-title {
    font-size: 0.9rem;
  }
  
  .masonry-action-btn {
    width: 40px;
    height: 40px;
    font-size: 1rem;
  }
}

@media (max-width: 480px) {
  .masonry-container {
    columns: 1;
    column-gap: 0;
  }
  
  .masonry-item {
    margin-bottom: 0.5rem;
  }
  
  .masonry-content {
    padding: 0.5rem;
  }
}

/* 图片预览模态框样式 */
.preview-modal {
  padding: 0;
}

.preview-modal :deep(.ant-modal-content) {
  padding: 0;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  border-radius: 16px;
  overflow: hidden;
}

.preview-modal :deep(.ant-modal-header) {
  border: none;
  padding: 0;
  background: transparent;
}

.preview-modal :deep(.ant-modal-body) {
  padding: 0;
}

.preview-modal :deep(.ant-modal-close) {
  position: fixed;
  top: 80px;
  right: calc(50% - 400px + 16px);
  color: #fff;
  background: rgba(0, 0, 0, 0.7);
  backdrop-filter: blur(10px);
  border-radius: 50%;
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1001;
  font-size: 16px;
  border: 2px solid rgba(255, 255, 255, 0.3);
  transition: all 0.3s ease;
}

.preview-modal :deep(.ant-modal-close:hover) {
  background: rgba(255, 59, 48, 0.8);
  border-color: rgba(255, 255, 255, 0.5);
  transform: scale(1.1);
}

.preview-container {
  position: relative;
  width: 100%;
  min-height: 400px;
  max-height: 80vh;
  display: flex;
  flex-direction: column;
}

.preview-image {
  width: 100%;
  height: auto;
  max-height: 60vh;
  object-fit: contain;
  background: #f5f5f5;
  border-radius: 16px 16px 0 0;
}

.preview-info {
  padding: 1.5rem;
  background: rgba(255, 255, 255, 0.9);
  backdrop-filter: blur(10px);
}

.preview-info h3 {
  margin: 0 0 1rem 0;
  font-size: 1.25rem;
  font-weight: 600;
  color: var(--primary-color);
  line-height: 1.4;
}

.preview-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-bottom: 1rem;
}

.preview-meta span {
  font-size: 0.9rem;
  color: #666;
  background: rgba(0, 0, 0, 0.05);
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  white-space: nowrap;
}

/* 黑色模式下的预览元数据 */
[data-theme="dark"] .preview-meta span {
  color: #9ca3af;
  background: rgba(255, 255, 255, 0.1);
}

.preview-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.preview-tag {
  font-size: 0.8rem;
  color: #4A90E2;
  background: rgba(74, 144, 226, 0.1);
  border: 1px solid rgba(74, 144, 226, 0.2);
  padding: 0.4rem 0.8rem;
  border-radius: 16px;
  transition: all 0.2s ease;
}

.preview-tag:hover {
  background: rgba(74, 144, 226, 0.2);
  border-color: rgba(74, 144, 226, 0.3);
}

/* 响应式适配 */
@media (max-width: 768px) {
  .preview-modal :deep(.ant-modal-content) {
    margin: 1rem;
    max-height: 90vh;
  }
  
  .preview-modal :deep(.ant-modal-close) {
    position: fixed;
    top: 20px;
    right: 20px;
    width: 36px;
    height: 36px;
  }
  
  .preview-container {
    max-height: 85vh;
  }
  
  .preview-image {
    max-height: 50vh;
  }
  
  .preview-info {
    padding: 1rem;
  }
  
  .preview-meta {
    flex-direction: column;
    gap: 0.5rem;
  }
  
  .preview-meta span {
    text-align: center;
  }
  
  .preview-tags {
    justify-content: center;
  }
}

@media (max-width: 480px) {
  .preview-modal :deep(.ant-modal-content) {
    margin: 0.5rem;
  }
  
  .preview-modal :deep(.ant-modal-close) {
    position: fixed;
    top: 15px;
    right: 15px;
    width: 32px;
    height: 32px;
    font-size: 14px;
  }
  
  .preview-info h3 {
    font-size: 1.1rem;
    text-align: center;
  }
  
  .preview-image {
    max-height: 40vh;
  }
}

/* 动画关键帧 */
@keyframes fadeInImage {
  from {
    opacity: 0;
    transform: scale(1.1);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}
</style>